package com.sky.service.impl;

import com.sky.dto.OrderReportDTO;
import com.sky.dto.TurnoverReportDTO;
import com.sky.dto.UserReportDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.vo.BusinessDataVO;
import com.sky.vo.OrderReportVO;
import com.sky.vo.TurnoverReportVO;
import com.sky.vo.UserReportVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        //1. 获取日期列表
        List<String> dateList = getDateList(begin, end);

        //2. 统计指定日期范围的营业额列表 - SQL
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);

        //2.1 查询数据库获取原始结果
        List<TurnoverReportDTO> turnoverReportDTOList = orderMapper.selectTurnoverList(beginTime, endTime, Orders.COMPLETED);

        //2.2 原始结果-->Map(key: 日期, value: 营业额)
        Map<String, BigDecimal> dataMap = turnoverReportDTOList.stream().collect(Collectors.toMap(TurnoverReportDTO::getOrderDate, TurnoverReportDTO::getOrderMoney));

        //2.3 遍历日期列表, 获取每一个日期对应的营业额, 如果没有营业额, 设置为0 ---> 集合
        List<BigDecimal> turnoverList = dateList.stream().map(date -> {
            return dataMap.get(date) == null ? new BigDecimal("0") : dataMap.get(date);
        }).collect(Collectors.toList());

        //3. 封装数据并返回
        return new TurnoverReportVO(dateList, turnoverList);
    }

    /**
     * 获取指定时间范围内的时间列表
     *
     * @param begin
     * @param end
     * @return
     */
    private List<String> getDateList(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = begin.datesUntil(end.plusDays(1)).collect(Collectors.toList());
        return dateList.stream().map(localDate -> {
            return localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }).collect(Collectors.toList());
    }


    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {

        // 1.获取日期列表
        List<String> dateList = getDateList(begin, end);

        //2. 获取指定时间范围内, 用户新增列表数据 - SQL .
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);

        // 2.1 查询原始数据
        List<UserReportDTO> userReportDTOList = userMapper.countAddByCreateTime(beginTime, endTime);

        // 2.2将原始数据转为map (key:日期，value:新增用户数量)
        Map<String, Integer> dataMap = userReportDTOList.stream().collect(Collectors.toMap(UserReportDTO::getCreateDate, UserReportDTO::getUserCount));

        // 2.3 遍历日期列表，从Map集合中获取数据，如果没有，就设置为0
        List<Integer> newUserList = dateList.stream().map(date -> dataMap.get(date) == null ? 0 : dataMap.get(date)).collect(Collectors.toList());


        // 3.获取指定时间范围内，用户总量列表数据
        // 3.1 查询开始时间之前，一共有多少个用户 基数 23
        Integer baseCount = userMapper.countTotalByCreateTime(begin);

        // 3.2 累加 -- 集合
        List<Integer> totalUserList = new ArrayList<>();
        for (Integer add : newUserList) {
            baseCount += add;
            totalUserList.add(baseCount);
        }

        return new UserReportVO(dateList, totalUserList, newUserList);
    }


    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {

        // 1.获取日期列表
        List<String> dateList = getDateList(begin, end);

        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);

        // 2.获取每日订单总数列表
        List<OrderReportDTO> orderReportDTOList = orderMapper.countOrderByOrderTimeAndStatus(beginTime, endTime, null);
        Map<String, Integer> orderMap = orderReportDTOList.stream().collect(Collectors.toMap(OrderReportDTO::getOrderDate, OrderReportDTO::getOrderCount));

        List<Integer> orderCountList = dateList.stream().map(date -> orderMap.get(date) == null ? 0 : orderMap.get(date)).collect(Collectors.toList());

        // 3.获取每日有效订单总是列表
        List<OrderReportDTO> validOrderReportDTOList = orderMapper.countOrderByOrderTimeAndStatus(beginTime, endTime, Orders.COMPLETED);
        Map<String, Integer> validOrderMap = validOrderReportDTOList.stream().collect(Collectors.toMap(OrderReportDTO::getOrderDate, OrderReportDTO::getOrderCount));

        List<Integer> validOrderCountList =  dateList.stream().map(date -> validOrderMap.get(date) == null ? 0 : validOrderMap.get(date)).collect(Collectors.toList());

        // 4.订单总数 -- orderCountList中的数据累加
        Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();

        // 5.订单完成率 -- orderCountList中的数据累加
        Integer orderCount = orderCountList.stream().reduce(Integer::sum).get();

        // 订单完成率
        Double i = orderCount.doubleValue() / totalOrderCount;

        return new OrderReportVO(dateList,orderCountList,validOrderCountList,totalOrderCount,orderCount,i);
    }

    @Autowired
    HttpServletResponse response;

    @Override
    public void exportData() throws Exception {
        // 1.获取近一个月的时间 - 开始 , 结束
        LocalDate begin = LocalDate.now().minusDays(30);
        LocalDate end =  LocalDate.now().minusDays(1);


        // 2.调用Mapper接口查询数据中的原始数据 -- 数据概览
        BusinessDataVO businessDataVO = orderMapper.countByTime(LocalDateTime.of(begin, LocalTime.MIN),
                LocalDateTime.of(end, LocalTime.MAX));
        Integer newUserCount = userMapper.countByTime(LocalDateTime.of(begin,LocalTime.MIN),LocalDateTime.of(end,LocalTime.MAX));

        String rangeDate = "时间范围:" + begin.toString() + " 到 " + end.toString();

        // 4.加载报表Exccel模板文件
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("templates/运营数据报表模板.xlsx");
        Workbook workbook = new XSSFWorkbook(inputStream);
        Sheet sheet = workbook.getSheetAt(0);


        // 5.定位单元格填充数据 - 数据概览
        sheet.getRow(1).getCell(1).setCellValue(rangeDate); // 时间
        sheet.getRow(3).getCell(2).setCellValue(businessDataVO.getTurnover());  // 营业额
        sheet.getRow(3).getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());   // 订单完成率
        sheet.getRow(3).getCell(6).setCellValue(newUserCount); // 新增用户数
        sheet.getRow(4).getCell(2).setCellValue(businessDataVO.getValidOrderCount());   // 有效订单
        sheet.getRow(4).getCell(4).setCellValue(businessDataVO.getUnitPrice()); // 平均客单价


        //6. 调用Mapper接口查询数据中的原始数据  - 每一天的明细
        for (int i = 0; i < 30; i++) {
            //获取时间
            LocalDate everyDate = begin.plusDays(i);

            //6.1 查询每一天的运营信息
            BusinessDataVO _businessDataVO = orderMapper.countByTime(LocalDateTime.of(everyDate, LocalTime.MIN), LocalDateTime.of(everyDate, LocalTime.MAX));
            Integer _newUserCount = userMapper.countByTime(LocalDateTime.of(everyDate, LocalTime.MIN), LocalDateTime.of(everyDate, LocalTime.MAX));

            //6.2 填充数据
            Row row = sheet.getRow(7 + i);
            row.getCell(1).setCellValue(everyDate.toString()); //时间
            row.getCell(2).setCellValue(_businessDataVO.getTurnover()); //营业额
            row.getCell(3).setCellValue(_businessDataVO.getValidOrderCount()); //有效订单
            row.getCell(4).setCellValue(_businessDataVO.getOrderCompletionRate()); //订单完成率
            row.getCell(5).setCellValue(_businessDataVO.getUnitPrice()); //平均客单价
            row.getCell(6).setCellValue(_newUserCount); //新增用户数
        }


        // 6.下载文件 -流
        ServletOutputStream out = response.getOutputStream();
        workbook.write(out);        // 将Excel文件作为流，响应给浏览器

    }
}
